﻿namespace MVCSample.UI.Controllers
{
    using System;
    using System.IO;
    using System.Linq;
    using System.Web.Mvc;
    using Cik.Gapi4Net.Core.FluentInterface;
    using Cik.Gapi4Net.Domain.Input;
    using Core;
    using Models;

    public abstract class MultiViewController : Controller
    {
        private const string FORMAT_KEY = "format";
        public enum FileFormat { Html, Json, Xml, Partial, Clean }

        protected MultiViewController()
        {
            RequestedFormat = FileFormat.Html;
        }

        protected FileFormat RequestedFormat { get; private set; }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            var routeValues = filterContext.RouteData.Values;
            if (routeValues.ContainsKey(FORMAT_KEY))
            {
                var requestedFormat = routeValues[FORMAT_KEY].ToString();
                if (isValidFormat(requestedFormat))
                {
                    RequestedFormat = (FileFormat)Enum.Parse(typeof(FileFormat), requestedFormat, true);
                }
            }
        }

        private bool isValidFormat(string requestedFormat)
        {
            return Enum.GetNames(typeof(FileFormat)).Any(format => format.ToLower() == requestedFormat.ToLower());
        }

        protected ActionResult FormatView(string viewName, object viewModel)
        {
            switch (RequestedFormat)
            {
                case FileFormat.Html:
                    if (viewName != string.Empty)
                    {
                        return View(viewName, viewModel);
                    }
                    return View(viewModel);
                case FileFormat.Json:
                    return Json(viewModel);
                case FileFormat.Xml:
                    return new XmlResult(viewModel);
                case FileFormat.Partial:
                    //return View(this.ControllerContext.RouteData.Values["action"] + "Partial");
                    return PartialView(ControllerContext.RouteData.Values["action"] + "Partial");
                case FileFormat.Clean:
                    if (viewName != string.Empty)
                    {
                        return View(viewName, "~/Views/Shared/Clean.master", viewModel);
                    }
                    var v = View(viewModel);
                    v.MasterName = "~/Views/Shared/Clean.Master";
                    return v;
                default:
                    throw new FormatException(string.Concat("Cannot server the content in the request format: ", RequestedFormat));
            }
        }

        protected ActionResult FormatView(object viewModel)
        {
            return FormatView("", viewModel);
        }

        protected string RenderPartialViewToString()
        {
            return RenderPartialViewToString(null, null);
        }

        protected string RenderPartialViewToString(string viewName)
        {
            return RenderPartialViewToString(viewName, null);
        }

        protected string RenderPartialViewToString(object model)
        {
            return RenderPartialViewToString(null, model);
        }

        protected string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");
            ViewData.Model = model;
            using (var sw = new StringWriter())
            {
                var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);
                return sw.GetStringBuilder().ToString();
            }
        }

        protected JsonResult GetJsonResult(string partialViewName, ModelBase model)
        {
            return Json(new
            {
                SubView = RenderPartialViewToString(partialViewName, model)
            });
        }

        protected T GetJsonFactory<T>(string searchText) where T : IEntity, new()
        {
            return Gapi4NetFactory<T>
                .Init()
                .With(x => x.Version, "1.0")
                .With(x => x.Query, searchText)
                .Create();
        }

        protected T PostJsonFactory<T>(string searchText, int start) where T : IEntity, new()
        {
            var factory = Gapi4NetFactory<T>
                .Init()
                .With(x => x.Version, "1.0")
                .With(x => x.Query, searchText);

            if (start >= 0)
            {
                factory.With(x => x.Start, start);
            }

            return factory.Create();
        }

        protected void SetTitle<T>(T model, string title) where T : IModel
        {
            model.Title = title;
        }
    }
}